<?php
class ClsNaanalModule extends ClsNaanalValidate
{
    private $module="home";
    private $action="create";
    private $switch="default";
    private $isSubmit=false;
    private $lang="default";
    public $homepage="";
    private $rand=false;
    public $controlpanel="";
    public $isAutoSubmitButton=false;
    public $id=0;
    public $parentModule="";
    public $parentAction="";
    public $parentModuleID=0;
    public $rootModule="";
    public $rootAction="";
    public $rootModuleID=0;
    public $isConfigExist=true;
    public $isFieldExist=true;
    public $isActionExist=false;
    public $isTableExist=false;
    public $isModuleExistInDB=true;
    public $arrValidate=array();
    public $files=array();
    private $arrTokenInfo=array();
    
    public $arrConfigVar=array();
    
    private $arrAdditionalInput=array();
    public $objParentModule=null;
    private $objControllerObject=null;
    private $objWrapperObject=null;
    public $arrWhere=array();
    
    private $arrError=array();
    private $modulePath="";
    private $isWorkPlace=true;
    private $isFrameworkModule=false;
    private $arrHeaderData=array();
    private $arrLang=array();
    
    public function __construct($module,$action,$id=0,$arrWhere=array(),$parentModuleID=0)
    {
        $this->module=$module;
        $this->action=$action;
        $this->id=$id;
        $this->modulePath=ClsNaanalApplication::getAbsModulePath($module,$action);
        if(strpos($this->modulePath, NAANAL_PATH)===0)
        {
            $this->isFrameworkModule=true;
        }
        $this->isWorkPlace=false;
        $workplacePath=ClsNaanalApplication::__getWorkplacePath();
        if($this->modulePath==$workplacePath)
        {
            $this->isWorkPlace=true;
        }
        else if($this->modulePath)
        {
            $this->arrConfigVar=ClsNaanalApplication::getConfigVars($module);
            $this->isConfigExist=true; 
        }
        if(isset($this->arrConfigVar["database"]))
        {
            $moduleDatabase=$this->arrConfigVar["database"];
            if($moduleDatabase===false || !class_exists("ClsConfig"))
            {
            }
            else
            {
                $moduleDatabase=$moduleDatabase===true?ClsNaanalApplication::getDefaultDatabase():$moduleDatabase;
                if($moduleDatabase=="naanal_default")
                {
                    
                }
                else if($moduleDatabase===false || is_null($moduleDatabase))
                {
                    
                }
                else
                {
                    $this->objWrapperObject=ClsWrapper::getInstance($module);
                    $modulePDO=ClsNaanalPDO::getModuleInstance($module, $moduleDatabase, getAppConfig("DATABASE_USER"), getAppConfig("DATABASE_PASSWORD"));
                    ///if install directory exist in module directory
                    if(file_exists($this->modulePath."install"))
                    {
                        $objInstall= new ClsNaanalInstall($module,$moduleDatabase);
                        $objInstall->addXML($this->modulePath."install/{$module}.xml");
                        $objInstall->render();
                    }
                }
            }
        }
        if($this->modulePath)
        {
            ClsNaanalApplication::loadController($module);
        }
        $this->parentModuleID=$parentModuleID;
        $this->arrTokenInfo=array
        (
            T_ABSTRACT => 'abstract => Class Abstraction (available since PHP 5.0.0)',
            T_AND_EQUAL => '&= => assignment operators',
            T_ARRAY => 'array() => array(), array syntax',
            T_ARRAY_CAST => '(array) => type-casting',
            T_AS => 'as => foreach',
            T_BAD_CHARACTER => '  => anything below ASCII 32 except \t (0x09), \n (0x0a) and \r (0x0d)',
            T_BOOLEAN_AND => '&& => logical operators',
            T_BOOLEAN_OR => '|| => logical operators',
            T_BOOL_CAST => '(bool) or (boolean) => type-casting',
            T_BREAK => 'break => break',
            T_CASE => 'case => switch',
            T_CATCH => 'catch => Exceptions (available since PHP 5.0.0)',
            T_CHARACTER => '  => not used anymore',
            T_CLASS => 'class => classes and objects',
            T_CLASS_C => '__CLASS__ => magic constants (available since PHP 4.3.0)',
            T_CLONE => 'clone => classes and objects (available since PHP 5.0.0)',
            T_CLOSE_TAG => '?> or %> => escaping from HTML',
            T_COMMENT => '// or #, and /* */ in PHP 5 => comments',
            T_CONCAT_EQUAL => '.= => assignment operators',
            T_CONST => 'const => class constants',
            T_CONSTANT_ENCAPSED_STRING => '\'foo\' or \'bar\' => string syntax',
            T_CONTINUE => 'continue => continue',
            T_CURLY_OPEN => '{$ => complex variable parsed syntax',
            T_DEC => '-- => incrementing/decrementing operators',
            T_DECLARE => 'declare => declare',
            T_DEFAULT => 'default => switch',
            T_DIV_EQUAL => '/= => assignment operators',
            T_DNUMBER => '0.12, etc => floating point numbers',
            T_DOC_COMMENT => '/** */ => PHPDoc style comments (available since PHP 5.0.0)',
            T_DO => 'do => do..while',
            T_DOLLAR_OPEN_CURLY_BRACES => '${ => complex variable parsed syntax',
            T_DOUBLE_ARROW => '=> => array syntax',
            T_DOUBLE_CAST => '(real), (double) or (float) => type-casting',
            T_DOUBLE_COLON => ':: => see T_PAAMAYIM_NEKUDOTAYIM below',
            T_ECHO => 'echo => echo',
            T_ELSE => 'else => else',
            T_ELSEIF => 'elseif => elseif',
            T_EMPTY => 'empty => empty()',
            T_ENCAPSED_AND_WHITESPACE => '" $a" => constant part of string with variables',
            T_ENDDECLARE => 'enddeclare => declare, alternative syntax',
            T_ENDFOR => 'endfor => for, alternative syntax',
            T_ENDFOREACH => 'endforeach => foreach, alternative syntax',
            T_ENDIF => 'endif => if, alternative syntax',
            T_ENDSWITCH => 'endswitch => switch, alternative syntax',
            T_ENDWHILE => 'endwhile => while, alternative syntax',
            T_END_HEREDOC => '  => heredoc syntax',
            T_EVAL => 'eval() => eval()',
            T_EXIT => 'exit or die => exit(), die()',
            T_EXTENDS => 'extends => extends, classes and objects',
            T_FILE => '__FILE__ => magic constants',
            T_FINAL => 'final => Final Keyword (available since PHP 5.0.0)',
            T_FOR => 'for => for',
            T_FOREACH => 'foreach => foreach',
            T_FUNCTION => 'function or cfunction => functions',
            T_FUNC_C => '__FUNCTION__ => magic constants (available since PHP 4.3.0)',
            T_GLOBAL => 'global => variable scope',
            T_HALT_COMPILER => '__halt_compiler() => __halt_compiler (available since PHP 5.1.0)',
            T_IF => 'if => if',
            T_IMPLEMENTS => 'implements => Object Interfaces (available since PHP 5.0.0)',
            T_INC => '++ => incrementing/decrementing operators',
            T_INCLUDE => 'include() => include',
            T_INCLUDE_ONCE => 'include_once() => include_once',
            T_INLINE_HTML => '  => text outside PHP',
            T_INSTANCEOF => 'instanceof => type operators (available since PHP 5.0.0)',
            T_INT_CAST => '(int) or (integer) => type-casting',
            T_INTERFACE => 'interface => Object Interfaces (available since PHP 5.0.0)',
            T_ISSET => 'isset() => isset()',
            T_IS_EQUAL => '== => comparison operators',
            T_IS_GREATER_OR_EQUAL => '>= => comparison operators',
            T_IS_IDENTICAL => '=== => comparison operators',
            T_IS_NOT_EQUAL => '!= or <> => comparison operators',
            T_IS_NOT_IDENTICAL => '!== => comparison operators',
            T_IS_SMALLER_OR_EQUAL => '<= => comparison operators',
            T_LINE => '__LINE__ => magic constants',
            T_LIST => 'list() => list()',
            T_LNUMBER => '123, 012, 0x1ac, etc => integers',
            T_LOGICAL_AND => 'and => logical operators',
            T_LOGICAL_OR => 'or => logical operators',
            T_LOGICAL_XOR => 'xor => logical operators',
            T_METHOD_C => '__METHOD__ => magic constants (available since PHP 5.0.0)',
            T_MINUS_EQUAL => '-= => assignment operators',
            T_MOD_EQUAL => '%= => assignment operators',
            T_MUL_EQUAL => '*= => assignment operators',
            T_NEW => 'new => classes and objects',
            T_NUM_STRING => '"$a[0]" => numeric array index inside string',
            T_OBJECT_CAST => '(object) => type-casting',
            T_OBJECT_OPERATOR => '-> => classes and objects',
            T_OPEN_TAG => '<?php, <? or <% => escaping from HTML',
            T_OPEN_TAG_WITH_ECHO => '<?= or <%= => escaping from HTML',
            T_OR_EQUAL => '|= => assignment operators',
            T_PAAMAYIM_NEKUDOTAYIM => ':: => ::. Also defined as T_DOUBLE_COLON.',
            T_PLUS_EQUAL => '+= => assignment operators',
            T_PRINT => 'print() => print',
            T_PRIVATE => 'private => classes and objects (available since PHP 5.0.0)',
            T_PUBLIC => 'public => classes and objects (available since PHP 5.0.0)',
            T_PROTECTED => 'protected => classes and objects (available since PHP 5.0.0)',
            T_REQUIRE => 'require() => require',
            T_REQUIRE_ONCE => 'require_once() => require_once',
            T_RETURN => 'return => returning values',
            T_SL => '<< => bitwise operators',
            T_SL_EQUAL => '<<= => assignment operators',
            T_SR => '>> => bitwise operators',
            T_SR_EQUAL => '>>= => assignment operators',
            T_START_HEREDOC => '<<< => heredoc syntax',
            T_STATIC => 'static => variable scope',
            T_STRING => '"parent" => identifiers, e.g. strings, object oriented keywords like parent and self, functions, classes and more are matched.',
            T_STRING_CAST => '(string) => type-casting',
            T_STRING_VARNAME => '"${a => complex variable parsed syntax',
            T_SWITCH => 'switch => switch',
            T_THROW => 'throw => Exceptions (available since PHP 5.0.0)',
            T_TRY => 'try => Exceptions (available since PHP 5.0.0)',
            T_UNSET => 'unset() => unset()',
            T_UNSET_CAST => '(unset) => type-casting (available since PHP 5.0.0)',
            T_VAR => 'var => classes and objects',
            T_VARIABLE => '$foo => variables',
            T_WHILE => 'while => while, do..while',
            T_WHITESPACE => '\t \r\n =>  ',
            T_XOR_EQUAL => '^= => assignment operators'
        );
        $this->arrWhere=$arrWhere;
        if(!ClsNaanalApplication::$isApplicationHasError) addLog("Module: $this->module, Action: $this->action, Module Path: $this->modulePath");
    }
    public function isFrameworkModule()
    {
        return $this->isFrameworkModule;
    }
    public function setSwitch($switch)
    {
        $this->switch=$switch;
    }
    public function setSubmit()
    {
        $this->isSubmit=true;
    }
    public function getError()
    {
        return $this->arrError;
    }
    public function setRand($rand)
    {
        $this->rand=$rand;
    }
    public function loadLanguage($name="default")
    {
        $langPathGlobal="lang/{$name}/";
        $langPathModule=$this->modulePath."lang/{$name}/";
        if(file_exists($langPathGlobal."common.php")) $this->arrLang=$this->getLangArray($langPathGlobal."common.php");
        else $this->arrLang=array();
        $arrLangModule=$this->getLangArray($langPathModule."common.php");
        foreach($arrLangModule as $standardCaption=>$langCaption)
        {
            $this->arrLang[$standardCaption]=$langCaption;
        }
    }
    private function getLangArray($langPath)
    {
        include $langPath;
        return isset($lang)?$lang:array();
    }
    public function getConfigVar($name)
    {
        if(array_key_exists($name,$this->arrConfigVar))
        {
            return $this->arrConfigVar[$name];
        }
        else if($this->isWorkPlace)
        {
            ///if the page loads from workplace, the theme is default to true and the ClsConfig's theme will be used
            if($name=="theme")
            {
                return true;
            }
            else
                return false;
        }
        else
        {
            return null;
        }
    }
    public function setConfigTable($table)
    {
        if(array_key_exists("table", $this->arrConfigVar))
        {
            if(is_null($this->arrConfigVar["table"]))
            {
                $this->arrConfigVar["table"]=$table;
                return true;
            }
        }
        return false;
    }
    public function addAdditionalInput($var,$data)
    {
        $this->arrAdditionalInput[$var]=$data;
    }
    public function setAction($action)
    {
        $this->action=$action;
    }
    public function __set($name, $value) 
    {
        $this->arrAdditionalInput[$name]=$value;
    }
    public function __get($name) 
    {
        return $this->arrAdditionalInput[$name];
    }
    public function isTableExist()
    {
        $pdo=ClsNaanalPDO::getNamedInstance();
        return $pdo->isTableExist($this->module);
    }
    public function createModule($arrFields)
    {
        $objWrapper=ClsWrapper::getInstance($this->module);
        if(!$objWrapper->isTableExist())
        {
            $objWrapper->createTable();
        }
        foreach($arrFields as $field=>$arrData)
        {
            if(!$objWrapper->isFieldExist($field))
            {
                $objWrapper->addField($field,$arrData["type"],$arrData["size"]);
            }
        }
    }
    public function isModule() 
    {
        if($this->isWorkPlace)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
    public static function isModuleExist($module)
    {
        $exist=ClsNaanalApplication::getAbsModulePath($module);
        if($exist===false) return false;
        else return true;
    }
    public function loadUtils()
    {
        if(file_exists("utils/".$this->module.".php"))
        {
            require_once "utils/".$this->module.".php";
        }
        if($this->isWorkPlace)
        {
            if($this->isWorkPlace)
            {
                if(file_exists("{$this->modulePath}{$this->module}_utils.php"))
                {
                    require_once "{$this->modulePath}{$this->module}_utils.php";
                }
            }
            else
            {
                if(file_exists("{$this->modulePath}{$this->module}/utils.php"))
                {
                    require_once "{$this->modulePath}{$this->module}/utils.php";
                }
            }
        }
    }
    public function &getWrapperObject()
    {
        return $this->objWrapperObject;
    }
    public function getModule()
    {
        return $this->module;
    }
    public function getAction()
    {
        return $this->action;
    }
    public function getSwitch()
    {
        return $this->switch;
    }
    public function setWhere($field,$data,$condition="=",$boolean="AND")
    {
        $this->arrWhere[]=array("field"=>$field,"data"=>$data,"condition"=>$condition,"boolean"=>$boolean);
    }
    public function render()
    {
        $cpanel=getCurrentControlPanel();
        
        $arrTemplateVariable=array();
        $arrTemplateVariable["module"]=$this->module;
        $arrTemplateVariable["action"]=$this->action;
        if(!defined("NAANAL_".strtoupper($this->module)."_ACTION"))define("NAANAL_".strtoupper($this->module)."_ACTION",$this->action);
        $out=null;
        if($this->isFrameworkModule)
        {
            $pageclass= "Cls".ucfirst($this->module);
        }
        else
        {
            $pageclass=  getModuleControllerName($this->module);
        }
        $arrRenderPage=null;
	if(file_exists($this->modulePath."utils.php"))
        {
            include_once($this->modulePath."utils.php");
	}
        if(file_exists($this->modulePath."{$pageclass}.php"))
        {
            include_once $this->modulePath."{$pageclass}.php";
            $this->objControllerObject=new $pageclass();
            ///deprecated
            ///start
            $this->objControllerObject->files=$this->files;
            ///end
            $this->objControllerObject->mode=$this->action;
            $this->objControllerObject->setModule($this->module);
            $this->objControllerObject->setAction($this->action);
            $this->objControllerObject->setSwitch($this->switch);
            $this->objControllerObject->init();
            $this->objControllerObject->objParentModule=$this->objParentModule;
            if(!empty($this->arrWhere))
            {
                foreach($this->arrWhere as $arrWhr)
                {
                    $this->objControllerObject->setWhere($arrWhr["field"],$arrWhr["data"],$arrWhr["condition"],$arrWhr["boolean"]);
                }
            }
            foreach($this->arrAdditionalInput as $var=>$addData)
            {
                $this->objControllerObject->addAdditionalInput($var,$addData);
            }
            if(property_exists($pageclass, "wrapper"))
            {
                $this->objControllerObject->wrapper=getModuleWrapperName($this->module);
            }
            ///deprecated
            ///start
            if($this->objControllerObject->files)
            {
                $this->objControllerObject->upload();
            }
            ///end
            else if(ClsNaanalFiles::getInstance("")->getAll())
            {
                $this->objControllerObject->upload();
            }
            /**
                * Main method of $this->objControllerObject overrides, default event method calling on an object\
                * if Main method not exists, the method(event - value set in the $this->action) will be called
                * if event not exist ignore the event
            */
            if($this->isFrameworkModule)
            {
                $mainMethodName="render";
            }
            else
            {
                $mainMethodName=getModuleControllerMainMethodName();
            }
            if(method_exists($this->objControllerObject, $mainMethodName))
            {
                $arrDecode=getModuleDecode(ClsNaanalRequest::getInstance()->getData("rand"));
                if(isset($arrDecode["action"]))
                {
                    $onMode="on".ucfirst($arrDecode["action"]);
                    if(method_exists($this->objControllerObject, $onMode))
                    {
                        $this->objControllerObject->$onMode();
                    }
                }
                $arrTplVar=$this->objControllerObject->$mainMethodName();
            }
            else
            {
                $mode=$this->action;
                $arrDecode=getModuleDecode(ClsNaanalRequest::getInstance()->getData("rand"));
                if(isset($arrDecode["action"]))
                {
                    $onMode="on".ucfirst($arrDecode["action"]);
                    if(method_exists($this->objControllerObject, $onMode))
                    {
                        $this->objControllerObject->$onMode();
                    }
                }
                if($mode=="list" && method_exists($this->objControllerObject, "show_list"))
                {
                    $arrTplVar=$this->objControllerObject->show_list();
                }
                else
                {
                    if(method_exists($this->objControllerObject, $mode)) 
                    {
                        $arrTplVar=$this->objControllerObject->$mode();
                    }
                }  
            }
            $modifiedAction=$this->objControllerObject->getModifiedAction();
            if($modifiedAction!==false)
            {
                $this->action=$modifiedAction;
            }
            $redirect=$this->objControllerObject->getRedirect();
            if(!is_null($redirect))
            {
                $redirect=empty($redirect)?$this->homepage:$this->homepage."?".$redirect;
                if( !headers_sent() )
                {
                    header("Location:{$redirect}");
                }
                else
                {
                    echo "<script type='text/javascript'>
                    document.location.href='{$redirect}';
                    </script>
                    Redirecting to <a href='{$redirect}'>Client List</a>";
                }
                exit;
            }
            if(isset($arrTplVar))
            {
                if(is_null($arrTplVar)){}
                else if(!is_array($arrTplVar))
                {
                        echo $arrTplVar;
                        return;
                }
                if(empty($arrTplVar)) 
                {
                    $form=ClsWrapper::getInstance($this->module);
                }
            }
            /// processing sub template - start
            $arrSubTemplate=$this->objControllerObject->getSubTemplate();
            if(!empty($arrSubTemplate))
            {
                foreach($arrSubTemplate as $subTemplateName=>$arrSubTemplateData)
                {
                    $arrTplVar[$subTemplateName]=$this->processTemplate($arrSubTemplateData["module"], $arrSubTemplateData["module"]."_".$arrSubTemplateData["action"], $arrSubTemplateData["arrTplVar"], $arrSubTemplateData["action"], $arrSubTemplateData["switch"]);
                } 
            }
            /// processing sub template - end
            ///processing global tpl var - start
            $arrGlobalTplVar=$this->objControllerObject->getGlobalTemplateVar();
            if(!empty($arrGlobalTplVar))
            {
                foreach($arrGlobalTplVar as $globalTplVar=>$globalTplData)
                {
                    if(!isset($arrTplVar[$globalTplVar]))
                    {
                        $arrTplVar[$globalTplVar]=$globalTplData;
                    }
                }
            }
            ///processing global tpl var - end
            $arrTplVar["controlpanel"]["value"]=$cpanel;
            $arrTplVar["home_page"]["value"]=$this->homepage;
            if(isset($arrTplVar["page"]))
            {
                    $arrRenderPage=$arrTplVar["page"];
                    unset($arrTplVar["page"]);
            }
        }
        if(!isset($arrTplVar))
        {
            $arrTplVar=array();
        }
        $arrTplVar["url_module_param"]=ClsNaanalRequest::getInstance()->getUrlModuleParam();
        $arrTplVar["url_action_param"]=ClsNaanalRequest::getInstance()->getUrlActionParam();
        $arrTplVar["url_switch_param"]=ClsNaanalRequest::getInstance()->getUrlSwitchParam();
        $arrTplVar["rand"]=$this->rand;
        $arrTplVar["module"]["value"]=$this->module;
        $arrTplVar["action"]["value"]=$this->action;
        $arrTplVar["switch"]=$this->switch;
        $arrTplVar["module_path"]["value"]=$this->modulePath;
        foreach($arrTemplateVariable as $templateVariable=>$templateVariableData)
        {
            $arrTplVar[$templateVariable]=$templateVariableData;
        }
        $workplacePath=ClsNaanalApplication::__getWorkplacePath();
        if($this->action=="list")
        {
            $listFile=false;
            if(file_exists("{$workplacePath}{$this->module}_list.php"))
            {
                $listFile="{$workplacePath}{$this->module}_list.php";
            }
            else if(file_exists($this->modulePath."list.php")) $listFile=$this->modulePath."list.php";
            $out=$this->processListTemplate($arrTplVar);
            $arrTplVar["out"]=$out;
        }
        else if($this->action=="forgot")
        {
            $arrVar=array();
            $arrVar["home_page"]["value"]=$this->homepage;
            $arrVar["control_panel"]["value"]=$cpanel;
            $arrVar["rand"]["value"]=$this->rand;
            $arrVar["module"]["value"]=$this->module;
            $arrVar["action"]["value"]=$this->action;
            $arrVar["module_path"]["value"]=$this->modulePath;
            $out="";
            $out = $out.$this->processTemplate($this->module,$this->module."_".$this->action,$arrVar,$this->action,$this->switch);
        }
        else
        {
            if(isset($arrTplVar["form"]) && $this->module!="modconfig" && $this->module!="naanalmodule")
            {
                $arrListVar=array();
                $form=$arrTplVar["form"];
                if(is_object($form))
                {
                    $arrListVar["id"]=array("value"=>$arrTplVar["form"]->get_id());
                    if(!empty($this->arrConfigVar["fields"]))
                    foreach($this->arrConfigVar["fields"] as $tmpfld=>$tmpdata)
                    {
                        if(isset($arrTplVar[$tmpfld])) continue;
                        $tmpfldform="get_{$tmpfld}";
                        $arrListVar[$tmpfld]=array("value"=>$arrTplVar["form"]->$tmpfldform());
                    }
                    $arrTplVar["listvar"]=$arrListVar;
                }
                else
                {
                    $arrListVar["id"]=array("value"=>$arrTplVar["form"]["id"]);
                    if(!empty($this->arrConfigVar["fields"]))
                    foreach($this->arrConfigVar["fields"] as $tmpfld=>$tmpdata)
                    {
                        if(isset($arrTplVar[$tmpfld])) continue;
                        $arrListVar[$tmpfld]=array("value"=>$arrTplVar["form"][$tmpfld]);
                    }
                    $arrTplVar["listvar"]=$arrListVar;
                }
            }
            $module_tpl=empty($this->objControllerObject)?$this->module:$this->objControllerObject->getModule();
            $action_tpl=empty($this->objControllerObject)?$this->action:$this->objControllerObject->getAction();
            $switch_tpl=empty($this->objControllerObject)?$this->switch:$this->objControllerObject->getSwitch();
            $out = $this->processTemplate($module_tpl,$module_tpl."_".$action_tpl,isset($arrTplVar)?$arrTplVar:null,$action_tpl,$switch_tpl);
        }  
        if(!is_null($arrRenderPage))
        {
            foreach($arrRenderPage as $renderpage=>$arrRenderParam)
            {
                $out = $this->renderPage($renderpage,"create",$arrRenderParam).$out;
            }
        }
        /*if(isset($arrTplVar["issubmit"]) && !$arrTplVar["issubmit"]){}
        else if($this->action=="create" || $this->action=="edit" || $this->action=="comps" || $this->module."_".$this->action=="comps_insert" || $this->action=="database")	
        {
            if(isset($arrTplVar["form"])) $out=$this->getForm($out);		
        }*/
        if(!empty($this->objControllerObject) && method_exists($this->objControllerObject, "onRender")) $this->objControllerObject->onRender($this->module,$this->action,$out);
       if($this->arrHeaderData) $this->objControllerObject->setHeaderData($this->arrHeaderData["title"],$this->arrHeaderData["js_include"],$this->arrHeaderData["css_include"]);
        //$this->objControllerObject=$page;
        return $out;
    }
    public function &getControllerObject()
    {
        return $this->objControllerObject;
    }
    public function &processListTemplate($arrTplVar)
    {
        $cpanel=getCurrentControlPanel();
        $listFile=false;
        $workplacePath=ClsNaanalApplication::__getWorkplacePath();
        if(file_exists("{$workplacePath}{$this->module}_list.php")) $listFile="{$workplacePath}{$this->module}_list.php";
        else if(file_exists($this->modulePath."list.php")) $listFile=$this->modulePath."list.php";
        if(!file_exists($this->modulePath."list_template.php"))
        {
            $out="<a href='{$this->homepage}?page={$this->module}'>Add New</a><br />";
        } 
        else
        {
            $out="";
        }
        
        /**
            * if database data exist and if the data set is not empty 
            */
        if(isset($arrTplVar["list"]) && !empty($arrTplVar["list"]))
        {
            $out=$out."
            <table class='list' id='tbl_list_".$this->module."'>";
            
            foreach($arrTplVar["list"] as $ind=>$form)
            {
                $arrListVar=array();
                foreach($arrTplVar as $var=>$data)
                {
                    if($var=="list") continue;
                    $arrListVar[$var]=$data;
                }
                if(is_object($form))
                {
                    $arrListVar["id"]=array("value"=>$form->get_id());
                    $arrListVar["home_page"]["value"]=$this->homepage;
                    $arrListVar["control_panel"]["value"]=$cpanel;
                    $arrListVar["rand"]["value"]=$this->rand;
                    $arrListVar["module"]["value"]=$this->module;
                    $arrListVar["action"]["value"]=$this->action;
                    $arrListVar["module_path"]["value"]=$this->modulePath;
                    foreach($this->arrConfigVar["fields"] as $tmpfld=>$tmpdata)
                    {
                        $tmpfldform="get_{$tmpfld}";
                        $arrListVar[$tmpfld]=array("value"=>$form->$tmpfldform());
                    }
                }
                else
                {
                    $arrListVar["id"]=array("value"=>$form["id"]);
                    $arrListVar["home_page"]["value"]=$this->homepage;
                    $arrListVar["control_panel"]["value"]=$cpanel;
                    $arrListVar["rand"]["value"]=$this->rand;
                    $arrListVar["module"]["value"]=$this->module;
                    $arrListVar["action"]["value"]=$this->action;
                    $arrListVar["module_path"]["value"]=$this->modulePath;
                    if(!empty($this->arrConfigVar["fields"]))
                    foreach($this->arrConfigVar["fields"] as $tmpfld=>$tmpdata)
                    {
                        $arrListVar[$tmpfld]=array("value"=>$form[$tmpfld]);
                    }
                }
                $arrListVar["record_index"]["value"]=$ind;
                $out = $out.$this->processTemplate($this->module,$listFile,$arrListVar,$this->action,$this->switch);
            }
        }
        $out=$out."</table>";
        
        if(isset($this->arrConfigVar["list_has_header"]) && $this->arrConfigVar["list_has_header"])
        {
            if(isset($arrTplVar["list"]))
            {
                unset($arrTplVar["list"]);
            }
            extract($arrTplVar);
            ob_start();
            include($this->modulePath.$this->action."_header.php");
            $out = ob_get_clean().$out;//$out.$this->processTemplate($this->module,$this->action."_header",null,$this->action);
        }
        
        $pagination="";
        if(isset($arrTplVar["pagination"])) $pagination=$arrTplVar["pagination"];
        if(file_exists($this->modulePath."list_template.php"))
        {
            ob_start();
            include $this->modulePath."list_template.php";
            $out=  ob_get_clean();
        }
        return $out;
    }
    public function validate()
    {
        if($this->isWorkPlace)
        {
            return true;
        }
        $arrConfigVarExpected=array("control_panel","database","table","theme","fields","actions","template_variables","template_function_calls");
        $isWrapperExist=true;
        $isControllerExist=true;
        $module=$this->module;
        $action=$this->action;
        $wrapper=  getModuleWrapperName($module);
        $controller=  getModuleControllerName($module);
        /**
         * validating the files
         */
        if($wrapper) $wrapperPath= "{$this->modulePath}{$wrapper}.php";
        else $wrapperPath=false;
        $controllerPath= "{$this->modulePath}{$controller}.php";
        if($this->isWorkPlace)
        {
            return true;
        }
        if(!file_exists($this->modulePath."lang"))
        {
            $this->arrValidate["FileNotFound"][]=$this->modulePath."lang/";
            $this->arrValidate["FileNotFound"][]=$this->modulePath."lang/default/";
            $this->arrValidate["FileNotFound"][]=$this->modulePath."lang/default/common.php";
        }
        else if(!file_exists($this->modulePath."lang/default"))
        {
            $this->arrValidate["FileNotFound"][]=$this->modulePath."lang/default/";
            $this->arrValidate["FileNotFound"][]=$this->modulePath."lang/default/common.php";
        }
        else if(!file_exists($this->modulePath."lang/default/common.php"))
        {
            $this->arrValidate["FileNotFound"][]=$this->modulePath."lang/default/common.php";
        }
        else
        {//trace("====");
            
        }
        if(!file_exists ($this->modulePath."config.php") && !file_exists ("module_config/{$module}.php"))
        {
            $this->isConfigExist=false;
            $this->arrValidate["FileNotFound"][]=$this->modulePath."config.php";
            $this->arrValidate["ConfigFileNotFound"]=true;
        }
        else
        {
            //$this->loadConfigVar();
            foreach($arrConfigVarExpected as $configVar)
            {
                if($configVar=="fields")
                {
                    if(array_key_exists("table", $this->arrConfigVar))
                    {
                        if($this->arrConfigVar["table"]===false || is_null($this->arrConfigVar["table"]))
                        {
                        }
                        else
                        {
                            if(!isset($this->arrConfigVar[$configVar]))
                            {
                                $this->arrValidate["ConfigVarNotFound"][]=$configVar;
                            }
                        }
                    }
                }
                else
                {
                    if(!array_key_exists($configVar, $this->arrConfigVar))
                    {
                        $this->arrValidate["ConfigVarNotFound"][]=$configVar;
                    }
                }
            }
        }

        if(array_key_exists("database", $this->arrConfigVar))
        {
            if($this->arrConfigVar["database"]===true)
            {
                if(ClsNaanalApplication::$isClsConfigExist && ClsNaanalApplication::$isDatabaseExist)
                {
                    $dbname=ClsNaanalApplication::getDefaultDatabase();
                }
            }
            else if($this->arrConfigVar["database"]===false)
            {
                $dbname=false;
            }
            else
            {
                $dbname=$this->arrConfigVar["database"];
            }
        }

        /**
         * validating the database
         */
	else if(!ClsNaanalApplication::$isApplicationHasError && isset($dbname) && $dbname!==false)
	{
		$arrIgnoreModuleRecord=array("clientmenu","menu","home");
		if(!in_array($this->module, $arrIgnoreModuleRecord))
		{
		    if(strpos($this->modulePath,NAANAL_PATH)===false)
		    {
		        $objWModule=ClsWrapper::getInstance("module");
		        $arrWhere=array
		        (
		            "field"=>"name",
		            "data"=>$this->module
		        );
                                                
		        $arrObject=$objWModule->searchObject($arrWhere);
		        $arrError=$objWModule->getError();
		        if($arrError)
		        {
		            foreach($arrError as $error)
		            {
		                $this->arrError[]=$error;
		            }
		            return false;
		        }
		        if(!$arrObject)
		        {
		            $this->isModuleExistInDB=false;
		            $this->arrValidate["ModuleRecordNotFound"][]=$this->module;
		        }
		    }
		}
	}
        if(!isset($this->arrConfigVar["table"]) || $this->arrConfigVar["table"]===false || is_null($this->arrConfigVar["table"]))
        {
            
        }
        else
        {
            if(isset($dbname) && $dbname===false) return true;
            /**
             * validate module table present
             */
            if(isset($dbname) && $dbname!==false && !isTableExist($dbname, $this->arrConfigVar["table"]))
            {
                $this->arrValidate["TableNotFound"][]=$this->arrConfigVar["table"];
            }
        }
        if(!file_exists($controllerPath))
        {
            $this->arrValidate["FileNotFound"][]=$controllerPath;
        }
        else
        {
            /**
            * verification of module controller start
            */
            include_once($controllerPath);
            if(!class_exists($controller))
            {
                $this->arrValidate["ClassNotFound"][]=array("class"=>$controller,"type"=>"controller","message"=>"Controller ({$controller}) not found");
            }
            else
            {
                $controllerContent=  file_get_contents($controllerPath);
                $arrControllerToken=  token_get_all($controllerContent);
                $isExtends=false;
                $isConstructorDefined=false;
                $count=count($arrControllerToken);
                for($i=0;$i<$count;$i++)
                {
                    $token=$arrControllerToken[$i];
                    if(!is_array($token)) continue;
                    if($token[1]=="extends")
                    {
                        $isExtends=true;
                        for($j=$i+1;$j<$count;$j++)
                        {
                            $tokennext=$arrControllerToken[$j];
                            if(!is_array($tokennext)) continue;
                            if($tokennext[1]=="__construct")
                            {
                                $isConstructorDefined=true;
                                break;
                                $i=$j+1;
                            }
                        }
                        if($isConstructorDefined) break;
                    }
                    if($isExtends) break;
                }
                
                $tmp_obj_controller_name=  ClsNaanalApplication::getControllerName($this->module);
                if(!$isConstructorDefined)
                {
                    if(isset($this->arrConfigVar["table"]))
                    {
                        $this->arrValidate["MethodNotFound"]["constructor"][]=array("class"=>$tmp_obj_controller_name,"method"=>"__construct","type"=>"controller","table"=>$this->arrConfigVar["table"],"message"=>"Method (__construct()) not found in the table {$this->arrConfigVar["table"]}");//array("method"=>"__construct","message"=>"Constructor method (__construct()) not found in the table {$this->arrConfigVar["table"]}");
                    }
                    else
                    {
                        $this->arrValidate["MethodNotFound"]["constructor"][]=array("class"=>$tmp_obj_controller_name,"method"=>"__construct","type"=>"controller","message"=>"Method (__construct()) not found");//array("method"=>"__construct","message"=>"Constructor method (__construct()) not found in the table {$this->arrConfigVar["table"]}");
                    }
                }
                if(!$isExtends)
                {
                    $this->arrValidate["ParentNotFound"][]=array("class"=>$tmp_obj_controller_name,"type"=>"controller","message"=>"Parent for Controller ({$tmp_obj_controller_name}) not found");
                }
                
                if($isConstructorDefined && $isExtends)
                {
                    if(isset($this->arrConfigVar["action"]) && !empty($this->arrConfigVar["action"]))
                    {
                        $tmpObjController=new $tmp_obj_controller_name($this->arrConfigVar["table"]);

                        foreach($this->arrConfigVar["action"] as $action=>$arrData)
                        {
                            if(!method_exists($tmpObjController, $action))
                            {
                                if($action=="list")
                                {
                                    $this->arrValidate["MethodNotFound"]["controller"][]=array("method"=>$action,"table"=>$this->arrConfigVar["table"],"message"=>"Method ({$action}()) not found for controller ".ClsNaanalApplication::getControllerName($module));
                                }
                                else
                                {
                                    $this->arrValidate["MethodNotFound"]["controller"][]=array("method"=>$action."_list","table"=>$this->arrConfigVar["table"],"message"=>"Method ({$action}_list()) not found for controller ".ClsNaanalApplication::getControllerName($module));
                                }
                            }
                        }
                    }
                }
            }
        }
        if($this->action=="list" && isset($this->arrConfigVar["list_has_header"]) && $this->arrConfigVar["list_has_header"] && !file_exists($this->modulePath."list_header.php"))
        {
            $this->arrValidate["FileNotFound"]=array
            (
                "file"=>$this->modulePath."list_header.php",
                "message"=>"List Header ({$this->modulePath}list_header.php) not found for module {$this->module}",
                "solution"=>"change \$list_has_header is false in module's config.php (or) create a {$this->modulePath}list_header.php file"
            );
        }
        if(!empty($this->arrValidate))
        {
            $this->arrError[]=$this->arrValidate;
            return false;
        }

        

        
        /**
        * verification of module controller end
        */
        return true;
    }
    public function setHeaderData($title,$arrJS=false,$arrCSS=false)
    {
        $this->arrHeaderData=array
        (
            "title"=>$title,
            "js_include"=>$arrJS,
            "css_include"=>$arrCSS
        );
    }
    public function getHeaderData()
    {
        return $this->arrHeaderData;
    }
    private function &loadTemplateFile($filePath,$arrTplVar=null)
    {
        
        if(!empty($this->arrLang))
        {
            extract($this->arrLang, EXTR_PREFIX_ALL, "LANG");
        }
        if(!empty($arrTplVar)) extract($arrTplVar); 
        unset($arrTplVar);
        if(!empty($listvar)) extract($listvar); 
        unset($listvar);
        $naanal_error=errMsg();
        if($this->getConfigVar("template_engine"))
        {
            $defined_vars=get_defined_vars();
            $objDLTE=ClsNaanalLibrary::getInstance("dlte");
            $obj=new PHP_DLTE();
            $obj->loadVar($defined_vars);
            $obj->loadLang($this->arrLang);
            $arrFilePath=explode(".",$filePath);
            $pop1=array_pop($arrFilePath);
            $pop2=array_pop($arrFilePath);
            if($pop2=="tpl")
            {
                $filePath=implode(".",$arrFilePath);
            }
            else
            {
                $filePath=implode(".",$arrFilePath).$pop2;
            }
            $out = $obj->display($filePath,true);
            return $out;
        }
        else
        {
            $entry=getEntryPoint();
            if($entry!==false)
            {
                if(file_exists("gate/{$entry}/before_include_template.php"))
                {
                    include("gate/{$entry}/before_include_template.php");
                }
            }
            ob_start();
            include($filePath);
            $out=  ob_get_clean();
            $entry=getEntryPoint();
            if($entry!==false)
            {
                if(file_exists("gate/{$entry}/after_include_template.php"))
                {
                    include("gate/{$entry}/after_include_template.php");
                }
            }
            return $out;
        }
    }
    function &processTemplate($page,$template,$arrTplVar=null,$mode=false,$switch="default")
    {
        $arrEncodeData=array();
        $arrEncodeData["module"]=$this->module;
        $arrEncodeData["action"]=$this->action;
        $arrEncodeData["switch"]=$this->switch;
        $this->setRand(getModuleEncode($arrEncodeData));
        $arrTplVar["rand"]=$this->rand;
        $tplPath="";//trace($this->module);
        $modulePath=  ClsNaanalApplication::getAbsModulePath($page);
        $workplacePath=  ClsNaanalApplication::__getWorkplacePath();
        ob_start();
        if($page=="show_trace")
        {
            $tplPath=NAANAL_PATH."phptrace/trace.html";
        }
        else if($mode!==false && $modulePath==NAANAL_PATH."modules/{$page}/" && file_exists(NAANAL_APP_PATH."{$workplacePath}{$page}_".$mode.".php"))
        {
            $tplPath=NAANAL_APP_PATH."{$workplacePath}{$page}_".$mode.".php";
        }
        else if($mode!==false && file_exists($modulePath.$mode.".php"))
        {
            $tplPath=$modulePath.$mode.".php";
        }
        else if($mode!==false && file_exists($modulePath."{$mode}/{$switch}.php"))
        {
            $tplPath=$modulePath."{$mode}/{$switch}.php";
        }
        else if($mode!==false && isset($this->arrConfigVar["template_engine"]) && $this->arrConfigVar["template_engine"] && file_exists($modulePath.$mode.".tpl.php"))
        {
            $tplPath=$modulePath.$mode.".tpl.php";
        }
        else if(file_exists($modulePath.$template.".php"))
        {
            $tplPath=$modulePath.$template.".php";
        }
        else if(file_exists($modulePath.$page.".php"))
        {
                $tplPath=$modulePath.$page.".php";
        }

        $naanal_error=errMsg();
        if(!empty($tplPath))
        {
            if(!ClsNaanalApplication::$isApplicationHasError && $this->isModule())
            {
                $arrToken=token_get_all(file_get_contents($tplPath));
                
                $arrAllowedToken=array 
                (
                    T_OPEN_TAG,
                    T_CONSTANT_ENCAPSED_STRING,
                    T_CLOSE_TAG,
                    T_EVAL,
                    T_PLUS_EQUAL,
                    T_MINUS_EQUAL,
                    T_CONCAT_EQUAL,
                    T_INLINE_HTML,
                    T_VARIABLE,
                    T_WHITESPACE,
                    T_EMPTY,
                    T_ECHO,
                    T_STRING,
                    T_ISSET,
                    T_OBJECT_OPERATOR,
                    T_DOUBLE_ARROW,
                    T_DOUBLE_COLON,
                    T_ENDFOREACH,
                    T_ARRAY,
                    T_LNUMBER,
                    T_INC,
                    T_COMMENT,
                    T_IS_GREATER_OR_EQUAL,
                    T_IS_SMALLER_OR_EQUAL,
                    T_CURLY_OPEN,
                    T_DOC_COMMENT,
                    T_RETURN,//allowed for coding neatness
                    ///comparision opearators
                    T_IS_IDENTICAL,
                    T_IS_NOT_IDENTICAL,
                    T_IS_GREATER_OR_EQUAL,
                    T_IS_SMALLER_OR_EQUAL,
                    T_IS_NOT_EQUAL,
                    T_IS_EQUAL,
                    ///end
                    ///logical operators
                    T_BOOLEAN_OR,
                    T_BOOLEAN_AND,
                    ///end
                    T_ENCAPSED_AND_WHITESPACE,
                    ///control structure
                    T_SWITCH,
                    T_CASE,
                    T_CONTINUE,
                    T_FOREACH,
                    T_FOR,
                    T_WHILE,
                    T_AS,
                    T_IF,
                    T_ELSE,
                    T_ELSEIF,
                    T_BREAK,
                    T_DEC,
                    ///end
                );
                if(isset(ClsConfig::$ALLOWED_TEMPLATE_TOKEN))
                {
                    $arrAllowedTokenNew=ClsConfig::$ALLOWED_TEMPLATE_TOKEN;
                    foreach($arrAllowedTokenNew as $atok)
                    {
                        if(!in_array($atok, $arrAllowedToken))
                        {
                            $arrAllowedToken[]=$atok;
                        }
                    }
                }
                $arrAllowedVariable=isset($this->arrConfigVar["template_variables"])?$this->arrConfigVar["template_variables"]:array();
                if($arrTplVar)
                {
                    foreach($arrTplVar as $tplk=>$tplv)
                    {
                        $arrAllowedVariable[]=$tplk;
                    }
                }
                $arrAllowedVariable[]="id";
                if(isset($this->arrConfigVar["fields"]) && !empty($this->arrConfigVar["fields"]))
                foreach($this->arrConfigVar["fields"] as $tmpfld=>$tmpdata) 
                {
                    $arrAllowedVariable[]=$tmpfld;
                }
                $isOtherError=false;
                $arrVariableError=array();
                if(IS_NAANAL_ADMIN===false) 
                {
                    $current_theme=$this->getConfigVar("theme")===true?ClsConfig::$theme:$this->getConfigVar("theme");
                    $arrTplVar["current_theme"]=$current_theme;
                    $arrAllowedVariable[]=$current_theme;

                    foreach($arrToken as $ind=>$data)
                    {
                        $isAllowed=false;
                        $isVariableError=false;
                        $isFunctionError=false;
                        if(!isset($data[2]) ||  in_array($data[0], $arrAllowedToken))
                        {
                            if($data[0]===T_VARIABLE)
                            {
                                if(in_array(substr($data[1],1), $arrAllowedVariable))
                                {
                                    $isAllowed=true;
                                }
                                else if($data[1]=='$module' || $data[1]=='$this' || $data[1]=='$url_module_param' || $data[1]=='$url_action_param' || $data[1]=='$home_page' || $data[1]=='$rand' || $data[1]=='$action' || $data[1]=='$message' || $data[1]=='$formodule' || $data[1]=='$foraction' || $data[1]=='$naanal_error')
                                {
                                    $isAllowed=true;
                                }
                                else
                                {
                                    $isVariableError=true;
                                }
                            }
                            else if($data[0]===T_FUNCTION)
                            {
                                $isFunctionError=true;
                            }
                            else
                            {
                                $isAllowed=true;
                            }
                        }
                        else
                        {
                            $isOtherError=true;
                        }
                        if($isVariableError)
                        {
                            $definedVar=$data[1];
                            if($definedVar=='$_REQUEST' || $definedVar=='$_POST' || $definedVar=='$_GET' || $definedVar=='$_SESSION')
                            {
                                $help="Usage of Super Globals such as \$_REQUEST, \$_POST, \$_GET and \$_SESSION are strictly restricted inside template";
                                $definedVar=  substr($definedVar, 1);
                            }
                            else
                            {
                                $definedVar=  substr($definedVar, 1);
                                $help="Variable other than defined in $page module's config.php is not allowed.";
                            }
                            $arrVariableError[$definedVar]["line"][$data[2]]="";
                            $arrVariableError[$definedVar]["help"]=$help;
                            $arrVariableError[$definedVar]["file"]=$tplPath;
                            $arrVariableError[$definedVar]["page"]=$template;
                        }
                        else if($isFunctionError)
                        {
                            trace("File: {$tplPath}, Page: {$template}, Line No.: {$data[2]}, Function '{$data[1]}' not allowed inside template. ", null, false, true, false, false, get_defined_vars());
                        }
                        else if($isOtherError)
                        {
                            $tokenname=  token_name($data[0]);
                            trace("File: {$tplPath}, Page: {$template}, Line No.: {$data[2]}, Element Type : {$tokenname} Element '{$data[1]}' not allowed inside template. ", null, false, true, false, false, get_defined_vars());
                        }
                    }
                }
                if(!empty($arrVariableError))
                {
                    $variMessage="";
                    $arrVarKey=  array_keys($arrVariableError);
                    foreach($arrVarKey as $vari)
                    {
                        $help=$arrVariableError[$vari]["help"];
                        $file=$arrVariableError[$vari]["file"];
                        $page=$arrVariableError[$vari]["page"];
                        $variMessage=$variMessage."<br />File: {$file}, Page: {$page}, Variable \${$vari} cannot be used inside template. <br />Help: ".$arrVariableError[$vari]["help"];
                        $variMessage=$variMessage."<br /> at Line No:";
                        $arrLine=  array_keys($arrVariableError[$vari]["line"]);
                        $variMessage=$variMessage.implode(", ",$arrLine);
                        $variMessage=$variMessage."<br />";
                    }
                    $variMessage=$variMessage."<br />Add the following in the module's config.php<br />";
                    foreach($arrVarKey as $vari)
                    {
                        if($vari=='_REQUEST' || $vari=='_GET' || $vari=='_POST' || $vari=='_SESSION' || $vari=='_SERVER') continue;
                        $variMessage=$variMessage."\$template_variables[]='{$vari}';<br />";
                    }
                    traceDirect($variMessage);
                }
            }
            echo $this->loadTemplateFile($tplPath, $arrTplVar);
            //include($tplPath); 
        }
        else if($mode=="list")
        {

        }
        else
        {
                echo "<center><h1>Page({$page}) or Page({$template}.php) or Page({$page}/{$mode}/{$switch}.php) Not Found</h1></center>";
        }
        $out=ob_get_clean();
        return $out;
    }
}
?>
